package com.amado.course53EncodeDecode;


import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


/**
 * 非对称加密算法RSA算法组件
 * 非对称算法一般是用来传送对称加密算法的密钥来使用的，相对于DH算法，RSA算法只需要一方构造密钥，不需要
 * 大费周章的构造各自本地的密钥对了。DH算法只能算法非对称算法的底层实现。而RSA算法算法实现起来较为简单
 *
 * -----BEGIN PUBLIC KEY-----
 * MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIwj4iC4CHSsD+t1WKo+9xVIhcUBkgBl
 * 5NL3rAjL/5OY8CmEePouqUUh5t5dnUssVxnQEeYSbSeqkZrziDXd7wcCAwEAAQ==
 * -----END PUBLIC KEY-----
 *
 * -----BEGIN RSA PRIVATE KEY-----
 * MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAjCPiILgIdKwP63VY
 * qj73FUiFxQGSAGXk0vesCMv/k5jwKYR4+i6pRSHm3l2dSyxXGdAR5hJtJ6qRmvOI
 * Nd3vBwIDAQABAkB8VE2HF56w3AIXtHkgOVJ+eGPtf1Intj6HiKIA//NT3tdD3c2T
 * tD5kV317DJ607/K52dwWjx+3ru3C6ssg9S0pAiEAzoGoyAYxQB6WLqKl5Nh5+jff
 * jiLgfV+JOuJGxFm6dm0CIQCtukZ9x6hRs80kyQruxN7KOdv0B/jwfLEdXpD5OYBi
 * wwIgUwghRCPxQ5XIzwGI8IX2LZyvn6f4WZDDTdDToXlultUCIA7wqgc/GFaOY+H5
 * +Bq4i4BQoX3HAb2Mu56O92C3dTcJAiAWSVQAOgMi4kRun8aoYwqK95A3hHhYh8yx
 * /UyuKkh7vA==
 * -----END RSA PRIVATE KEY-----
 * @author kongqz
 * 用http://tool.chacuo.net/cryptrsapubkey测试
 * JAVA代码生成的需要添加
 * -----BEGIN RSA PRIVATE KEY-----
 * -----END RSA PRIVATE KEY-----
 * 与换行
 */
public class RSADecodePKcs8 {
    //非对称密钥算法
    public static final String KEY_ALGORITHM = "RSA";


    /**
     * 密钥长度，DH算法的默认密钥长度是1024
     * 密钥长度必须是64的倍数，在512到65536位之间
     */
    private static final int KEY_SIZE = 512;
    //公钥
    private static final String PUBLIC_KEY = "RSAPublicKey";

    //私钥
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * 初始化密钥对
     *
     * @return Map 甲方密钥的Map
     */
    public static Map<String, Object> initKey() throws Exception {
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //甲方公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        //甲方私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        //将密钥存储在map中
        Map<String, Object> keyMap = new HashMap<String, Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;

    }


    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @param key       密钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {

        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     *
     * @param data 待加密数据
     * @param key       密钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {

        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {

        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }

    /**
     * 取得私钥
     *
     * @param keyMap 密钥map
     * @return byte[] 私钥
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }

    /**
     * 取得公钥
     *
     * @param keyMap 密钥map
     * @return byte[] 公钥
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();
    }

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //初始化密钥
        //生成密钥对
        Map<String, Object> keyMap = RSADecodePKcs8.initKey();


//        String strPrivateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJxwarz81K66uVtUNaUeAdH4nxaLF9z9gWbCTYSGUkOF84wz5/L8IGf7GSAp+J1YJXYVK1Y4unWI/A8Ic4BDjK+J3yp9LgtyUPHpGKrHhkcxYce0NIK3C8Ry2cuB4x0TOHYniD8rR45udoy6+XjyjetT4uCIqB+bCWdjuglJJislAgMBAAECgYAD6FbyM4qIdseMfXT9k9tNyF0I7h6BeZ+S1oWjKsvBPgZQWTeQ/TU+A6qkAAhivcHpyiuT8sTNjMdnBLoF2SoZalOSijmpjNnICnwQfEpvPjCTmIUPbqR9kc/cJhBXrh/ivZlIfYIqV8Uo1pGYx2xA7QocWrMbidOUWzE8Qi9LvQJBAN//7vN/O2LvqqBSkz7uPlgPCschVyu4KROcXbqZFoOv9CS7ZZ6D9RLSTR22f640VHqamwWanQ5v4N9+6btaEasCQQCyyawqaeH2xqHJ7iF8kJngE2+oUeMvYpYqAJoMBWnKjsjG5suqD8f4anKjSuUXJmWyzmMZG9wq12y/uHjwi4ZvAkAbMyK64po9e0jGywAiRh+/5aOzZnMFVgl23ifrfqdjOjx1MWQ3iWJ69Jp0nzKF3sjbUma8mXe0xxURToHnRBqdAkEAlO3pvGr3D9nma48x1dGeXEnUeSG9XXuCGvrlV54qwdCu7wDSJpd+vC/vzpZUvzP9AzVo10Gd5RIORKYmGDohgQJBANuiJ9Vyln1v2jRxWPEY80xRKj7LShBV5AbQr+D9hp3xeGHiy5oVybvCXjq+ktewe7PnNmX+13iaZQ0rL9/1n+4=";
//        String strPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCccGq8/NSuurlbVDWlHgHR+J8Wixfc/YFmwk2EhlJDhfOMM+fy/CBn+xkgKfidWCV2FStWOLp1iPwPCHOAQ4yvid8qfS4LclDx6Riqx4ZHMWHHtDSCtwvEctnLgeMdEzh2J4g/K0eObnaMuvl48o3rU+LgiKgfmwlnY7oJSSYrJQIDAQAB";


        String strPublicKey  = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCajLOdwFMIBQ8k3W48/e4bIj2E\n" +
                "Fc3O/T54oiLOk+KQgAknvmUHJp/1arN8g9tjAaBKPSbznTe4ZYX3VXI7VTRF7Dhi\n" +
                "1+vCkas1OwWkdwzZWg3LOqfUORF3tFmvNOiLLzJQ6H5oLsNNZjMOr2QZrm4srzc1\n" +
                "aX3O0BRwQhPkP/XhYwIDAQAB";

        strPublicKey =  strPublicKey.replaceAll("\n","");
        //公钥
        byte[] publicKey = Base64.getDecoder().decode(strPublicKey);
        String str = "fzAUyHQfMRSVCxYEo65ur9AwvZU/jM14cFLDPXtKwcl+WozZTblYwgJiU/zYRfE6\n" +
                "6YhC5leWT36/iyQFWA4sKHyxYUJusB48JpNf1GbfjslRaX6NSSZJ/8v+q6ANHsCT\n" +
                "U1YRUoNK1ShAmf+UTwPo31SLxzC6Vf8rTZHqEZa+GM8=";
        str = str.replaceAll("\n","");
        System.out.println("原文:" + str);

        //乙方使用公钥对数据进行加密
        byte[] code2 =Base64.getDecoder().decode(str);

        //甲方使用私钥对数据进行解密
        byte[] decode2 = RSADecodePKcs8.decryptByPrivateKey(code2, publicKey);

        System.out.println("甲方解密后的数据：" + new String(decode2));
    }
}